/*
 * @Author: bor_fish 1219854025@qq.com
 * @Date: 2025-04-26 19:58:11
 * @LastEditors: bor_fish 1219854025@qq.com
 * @LastEditTime: 2025-05-20 21:27:56
 * @FilePath: \SendCAN\main.cpp
 * @Description: CAN通信程序 - 上位机发送到驱动�?
 */
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <linux/can.h>
#include <linux/can/raw.h>
#include <net/if.h>
#include <time.h>  // 添加time.h头文件用于随机数种子
#include <sys/time.h>
// 定义常量
#define BASE_CAN_ID 0x32000  // 基础ID为32000
#define MIN_DEVICE_ID 2		//X的范围
#define MAX_DEVICE_ID 8		//X的范围

// 异常模拟参数
#define SEND_FAILURE_RATE 0.1    // 发送失败概率 10%
#define SEND_DELAY_MIN 50000     // 最小发送延迟 50ms，上位机发送数据到驱动器
#define SEND_DELAY_MAX 200000    // 最大发送延迟 200ms，上位机发送数据到驱动器
#define RECEIVE_TIMEOUT 500000   // 接收超时时间 500ms，超过此时间认为反馈超时，不再接收数据

// 指令帧结构
typedef struct {
    int16_t speed;        // 速度
    uint8_t fault_clear;  // 故障清零标志
} CommandFrame;
// 生成指定范围内的随机数
int get_random_value(int min, int max) {
    return min + (rand() % (max - min + 1));
}
// 将转速转换为CAN数据
void convert_speed_to_can_data(int16_t speed, uint8_t* data) {
    // 处理负数
    if (speed < 0) {
        speed = -speed;
        data[1] |= 0x80;  // 设置高位1表示负数
    }
    
    // 设置速度
    data[0] = speed & 0xFF;        // 低8位
    data[1] = (speed >> 8) & 0x7F; // 高7位
}

// 从CAN数据中提取速度和故障标志位
void extract_data_from_can(const uint8_t* data, int16_t* speed, uint8_t* fault_clear) {
    // 提取速度值
    *speed = (data[0] | ((data[1] & 0x7F) << 8));
    
    // 检查是否为负数
    if (data[1] & 0x80) {
        *speed = -*speed;
    }
    
    // 提取故障标志位
    *fault_clear = data[2];
}

// 模拟发送延迟
void simulate_send_delay() {
    int delay = get_random_value(SEND_DELAY_MIN, SEND_DELAY_MAX);
    usleep(delay);
}

// 模拟发送失败
bool simulate_send_failure() {
    return (rand() % 100) < (SEND_FAILURE_RATE * 100);
}

// 等待接收反馈
bool wait_for_feedback(int sockfd, uint32_t expected_id) {
    struct can_frame rx_frame;
    struct timeval start, now;
    gettimeofday(&start, NULL);

    while (1) {
        struct timeval tv;
        fd_set readfds;
        tv.tv_sec = 0;
        tv.tv_usec = 10000; // 每次最多等10ms

        FD_ZERO(&readfds);
        FD_SET(sockfd, &readfds);

        int ret = select(sockfd + 1, &readfds, NULL, NULL, &tv);
        if (ret > 0) {
            int nbytes = read(sockfd, &rx_frame, sizeof(rx_frame));
            if (nbytes > 0) {
                if (rx_frame.can_id == expected_id) {
                    return true;
                }
            }
        }
        // 检查是否超时
        gettimeofday(&now, NULL);
        long elapsed = (now.tv_sec - start.tv_sec) * 1000000L + (now.tv_usec - start.tv_usec);
        if (elapsed >= RECEIVE_TIMEOUT) {
            break;
        }
    }
    return false;
}

int main(int argc, char *argv[])
{
    if (argc < 2) {
        printf("用法: %s controller\n", argv[0]);
        return 1;
    }

    struct ifreq ifr = {0};
    struct sockaddr_can can_addr = {0};
    int sockfd = -1;
    int ret;

    // 打开套接字
    sockfd = socket(PF_CAN, SOCK_RAW, CAN_RAW);
    if (0 > sockfd) {
        perror("socket error");
        exit(EXIT_FAILURE);
    }

    // 指定can0设置
    strcpy(ifr.ifr_name, "vcan0");
    ioctl(sockfd, SIOCGIFINDEX, &ifr);
    can_addr.can_family = AF_CAN;
    can_addr.can_ifindex = ifr.ifr_ifindex;

    // 绑定
    ret = bind(sockfd, (struct sockaddr *)&can_addr, sizeof(can_addr));
    if (0 > ret) {
        perror("bind error");
        close(sockfd);
        exit(EXIT_FAILURE);
    }

    if (strcmp(argv[1], "controller") == 0) {
        // 控制装置逻辑
        // 设置过滤器，接收320X2格式的反馈ID
        struct can_filter rfilter[MAX_DEVICE_ID - MIN_DEVICE_ID + 1];
        int filter_count = 0;
        
        for (int device_id = MIN_DEVICE_ID; device_id <= MAX_DEVICE_ID; device_id++) {
            rfilter[filter_count].can_id = BASE_CAN_ID | (device_id << 4) | 0x2;
            rfilter[filter_count].can_mask = CAN_SFF_MASK;
            filter_count++;
        }
        
        setsockopt(sockfd, SOL_CAN_RAW, CAN_RAW_FILTER, rfilter, sizeof(rfilter));

        struct can_frame frame = {0};
        frame.can_dlc = 8;  // 固定8字节数据长度
        
        // 初始化随机数种子
        srand(time(NULL));

        while (1) {
            // 为每个设备发送指令
            for (int device_id = MIN_DEVICE_ID; device_id <= MAX_DEVICE_ID; device_id++) {
                // 设置CAN ID (320X1格式)
                frame.can_id = BASE_CAN_ID | (device_id << 4) | 0x1;

                // 生成0-10000之间的随机速度
                int16_t speed = rand() % 10001;  // 生成0-10000的随机数
                uint8_t fault_clear = rand() % 2;  // 生成0或1的随机数

                // 清空数据
                memset(frame.data, 0, 8);

                // 转换到CAN数据
                convert_speed_to_can_data(speed, frame.data);

                // 设置故障清零标志
                frame.data[2] = fault_clear;

                // 模拟发送延迟
                simulate_send_delay();

                // 模拟发送失败
                if (!simulate_send_failure()) {
                    // 发送数据
                    int ret = write(sockfd, &frame, sizeof(frame));
                    if (ret != sizeof(frame)) {
                        perror("write error");
                        break;
                    }

                    // 等待接收反馈
                    uint32_t expected_feedback_id = BASE_CAN_ID | (device_id << 4) | 0x2;
                    if (!wait_for_feedback(sockfd, expected_feedback_id)) {
                        printf("设备 0x%X 反馈超时\n", frame.can_id);
                    }

                    // 打印发送的数据
                    printf("发送到设备 0x%X: 速度=%d, 故障清零=%d\n", 
                           frame.can_id, speed, fault_clear);
                } else {
                    printf("设备 0x%X 发送失败\n", frame.can_id);
                }
            }

            // 发送间隔
            usleep(10000);  // 100ms
        }
    } else {
        printf("?模式: %s\n", argv[1]);
    }

    close(sockfd);
    return 0;
}